import { spawn } from 'child_process'
import { app } from 'electron'
import * as path from 'path'
import * as fs from 'fs'
export class FfmpegService {
  private getFfmpegPath(): string {
    if (app.isPackaged) {
      // 生产环境
      // 尝试直接在resourcesPath下查找
      let ffmpegPath = path.join(process.resourcesPath, 'ffmpeg.exe')
      if (fs.existsSync(ffmpegPath)) {
        return ffmpegPath
      }
      
      // 如果找不到，尝试在app.asar.unpacked/resources路径下查找
      ffmpegPath = path.join(process.resourcesPath, 'app.asar.unpacked', 'resources', 'ffmpeg.exe')
      if (fs.existsSync(ffmpegPath)) {
        return ffmpegPath
      }
      
      // 如果都找不到，返回默认路径（至少会在错误信息中显示尝试过的路径）
      return path.join(process.resourcesPath, 'ffmpeg.exe')
    } else {
      // 开发环境
      return path.join(__dirname, '../../resources/ffmpeg.exe')
    }
  }

  /**
   * 转换视频为M3U8格式
   * @param inputFile 输入文件路径
   * @param outputDir 输出目录
   * @param onProgress 进度回调
   */
  async convertToM3U8(
    inputFile: string, 
    outputDir: string, 
    onProgress?: (log: string) => void
  ): Promise<void> {
    return new Promise((resolve, reject) => {
      const ffmpegPath = this.getFfmpegPath()
      
      // 检查FFMpeg是否存在
      if (!fs.existsSync(ffmpegPath)) {
        throw new Error(`FFMpeg未找到: ${ffmpegPath}`)
      }

      // 检查输入文件是否存在
      if (!fs.existsSync(inputFile)) {
        throw new Error(`输入文件不存在: ${inputFile}`)
      }

      // 确保输出目录存在
      if (!fs.existsSync(outputDir)) {
        fs.mkdirSync(outputDir, { recursive: true })
      }

      const outputFile = path.join(outputDir, 'output.m3u8')
      
      const args = [
        '-i', inputFile,
        '-c:v', 'libx264',
        '-c:a', 'aac',
        '-hls_time', '10',
        '-hls_list_size', '0',
        '-f', 'hls',
        outputFile
      ]

      onProgress?.(`开始转换: ${inputFile} -> ${outputFile}`)
      
      const ffmpegProcess = spawn(ffmpegPath, args)

      ffmpegProcess.stdout.on('data', (data) => {
        const log = data.toString().trim()
        if (log) {
          onProgress?.(`INFO: ${log}`)
        }
      })

      ffmpegProcess.stderr.on('data', (data) => {
        const log = data.toString().trim()
        if (log) {
          onProgress?.(`FFMPEG: ${log}`)
        }
      })

      ffmpegProcess.on('close', (code) => {
        if (code === 0) {
          onProgress?.(`转换完成: ${outputFile}`)
          resolve()
        } else {
          reject(new Error(`FFMpeg进程退出码: ${code}`))
        }
      })

      ffmpegProcess.on('error', (error) => {
        reject(new Error(`FFMpeg进程错误: ${error.message}`))
      })
    })
  }

  /**
   * 检查FFMpeg是否可用
   */
  async checkFfmpeg(): Promise<boolean> {
    try {
      const ffmpegPath = this.getFfmpegPath()
      return fs.existsSync(ffmpegPath)
    } catch {
      return false
    }
  }

  /**
   * 从全景视频中提取帧
   * @param inputFile 输入文件路径
   * @param outputDir 输出目录
   * @param onProgress 进度回调
   */
  async extractPanoramaFrames(
    inputFile: string,
    outputDir: string,
    frameInterval: number = 0.5,
    resolution: string = '1920x1080',
    onProgress?: (log: string) => void
  ): Promise<void> {
    return new Promise((resolve, reject) => {
      const ffmpegPath = this.getFfmpegPath()
      
      // 检查FFMpeg是否存在
      if (!fs.existsSync(ffmpegPath)) {
        throw new Error(`FFMpeg未找到: ${ffmpegPath}`)
      }

      // 检查输入文件是否存在
      if (!fs.existsSync(inputFile)) {
        throw new Error(`输入文件不存在: ${inputFile}`)
      }

      // 确保输出目录存在
      if (!fs.existsSync(outputDir)) {
        fs.mkdirSync(outputDir, { recursive: true })
      }

      const fps = 1 / frameInterval
      const outputPattern = path.join(outputDir, 'frame_%04d.jpg')
      
      // 解析分辨率
      const [width, height] = resolution.split('x').map(Number);
      
      // 使用ffmpeg从全景视频中按0.5秒间隔抽取等矩形图像
      const args = [
        '-i', inputFile,
        '-vf', `fps=${fps},yadif,scale=${width}:${height}`, // 帧率、去隔行和缩放
        '-q:v', '2', // 高质量
        '-y', // 覆盖现有文件
        outputPattern
      ]

      onProgress?.(`开始提取全景视频帧: ${inputFile} -> ${outputDir}`)
      
      const ffmpegProcess = spawn(ffmpegPath, args)

      ffmpegProcess.stdout.on('data', (data) => {
        const log = data.toString().trim()
        if (log) {
          onProgress?.(`INFO: ${log}`)
        }
      })

      ffmpegProcess.stderr.on('data', (data) => {
        const log = data.toString().trim()
        if (log) {
          onProgress?.(`FFMPEG: ${log}`)
        }
      })

      ffmpegProcess.on('close', (code) => {
        if (code === 0) {
          onProgress?.(`全景视频帧提取完成: ${outputDir}`)
          resolve()
        } else {
          reject(new Error(`FFMpeg进程退出码: ${code}`))
        }
      })

      ffmpegProcess.on('error', (error) => {
        reject(new Error(`FFMpeg进程错误: ${error.message}`))
      })
    })
  }

  /**
   * 从全景视频中提取五个角度的透视图
   * @param inputFile 输入文件路径
   * @param outputDir 输出目录
   * @param frameInterval 帧间隔（秒）
   * @param onProgress 进度回调
   */
  async extractPanoramaProjections(
    inputFile: string,
    outputDir: string,
    frameInterval: number = 0.5,
    projectionType: '5views' | '8views' = '8views',
    resolution: string = '1920x1080',
    onProgress?: (log: string) => void
  ): Promise<void> {
    return new Promise((resolve, reject) => {
      const ffmpegPath = this.getFfmpegPath()
      
      // 检查FFMpeg是否存在
      if (!fs.existsSync(ffmpegPath)) {
        throw new Error(`FFMpeg未找到: ${ffmpegPath}`)
      }

      // 检查输入文件是否存在
      if (!fs.existsSync(inputFile)) {
        throw new Error(`输入文件不存在: ${inputFile}`)
      }

      // 确保输出目录存在
      if (!fs.existsSync(outputDir)) {
        fs.mkdirSync(outputDir, { recursive: true })
      }

      // 定义角度配置
      let angles: Array<{ id: string, yaw: number, pitch: number, roll: number }> = []
      
      if (projectionType === '5views') {
        // 5视图模式：前、后、左、右、上
        angles = [
          { id: 'front', yaw: 0, pitch: 0, roll: 0 },
          { id: 'back', yaw: 180, pitch: 0, roll: 0 },
          { id: 'left', yaw: -90, pitch: 0, roll: 0 },
          { id: 'right', yaw: 90, pitch: 0, roll: 0 },
          { id: 'up', yaw: 0, pitch: -90, roll: 0 }
        ]
      } else {
        // 8视图模式：前俯视、前仰视、后俯视、后仰视、左俯视、左仰视、右俯视、右仰视
        angles = [
          { id: 'front-down', yaw: 0, pitch: -30, roll: 0 },
          { id: 'front-up', yaw: 0, pitch: 30, roll: 0 },
          { id: 'back-down', yaw: 180, pitch: -30, roll: 0 },
          { id: 'back-up', yaw: 180, pitch: 30, roll: 0 },
          { id: 'left-down', yaw: -90, pitch: -30, roll: 0 },
          { id: 'left-up', yaw: -90, pitch: 30, roll: 0 },
          { id: 'right-down', yaw: 90, pitch: -30, roll: 0 },
          { id: 'right-up', yaw: 90, pitch: 30, roll: 0 }
        ]
      }

      // 创建各个角度的子目录
      for (const angle of angles) {
        const anglePath = path.join(outputDir, angle.id)
        if (!fs.existsSync(anglePath)) {
          fs.mkdirSync(anglePath)
        }
      }

      const fps = 1 / frameInterval
      onProgress?.(`开始提取全景视频${projectionType === '5views' ? '5视图' : '8视图'}透视图: ${inputFile} -> ${outputDir}`)

      try {
        // 使用Promise.all来并行处理五个角度
        Promise.all(angles.map(async (angle) => {
          return this.extractSpecificAngle(
            inputFile, 
            path.join(outputDir, angle.id), 
            angle.yaw, 
            angle.pitch, 
            angle.roll, 
            fps, 
            resolution,
            onProgress
          )
        })).then(() => {
          onProgress?.(`全景视频${projectionType === '5views' ? '5视图' : '8视图'}透视图提取完成: ${outputDir}`)
          resolve()
        }).catch(error => {
          reject(error)
        })
      } catch (error) {
        reject(error)
      }
    })
  }

  /**
   * 提取特定角度的透视图
   */
  private async extractSpecificAngle(
    inputFile: string,
    outputDir: string,
    yaw: number,
    pitch: number,
    roll: number,
    fps: number,
    resolution: string,
    onProgress?: (log: string) => void
  ): Promise<void> {
    return new Promise((resolve, reject) => {
      const ffmpegPath = this.getFfmpegPath()
      const outputPattern = path.join(outputDir, `frame_%04d.jpg`)
      
      // 解析分辨率
      // const [width, height] = resolution.split('x').map(Number);
      const [width] = resolution.split('x').map(Number);
      // 构建v360滤镜参数，使用用户提供的成功命令格式
      const v360Filter = `v360=input=e:output=rectilinear:yaw=${yaw}:pitch=${pitch}:roll=${roll}:h_fov=90:v_fov=90:w=${width}:h=${width}`

      const args = [
        '-i', inputFile,
        '-vf', `fps=${fps},yadif,${v360Filter}`,
        '-q:v', '2', // 高质量
        '-y', // 覆盖现有文件
        outputPattern
      ]

      onProgress?.(`开始提取角度(yaw=${yaw},pitch=${pitch},roll=${roll})的透视图`)
      
      const ffmpegProcess = spawn(ffmpegPath, args)

      ffmpegProcess.stdout.on('data', (data) => {
        const log = data.toString().trim()
        if (log) {
          onProgress?.(`INFO (yaw=${yaw},pitch=${pitch}): ${log}`)
        }
      })

      ffmpegProcess.stderr.on('data', (data) => {
        const log = data.toString().trim()
        if (log) {
          onProgress?.(`FFMPEG (yaw=${yaw},pitch=${pitch}): ${log}`)
        }
      })

      ffmpegProcess.on('close', (code) => {
        if (code === 0) {
          onProgress?.(`角度(yaw=${yaw},pitch=${pitch},roll=${roll})的透视图提取完成`)
          resolve()
        } else {
          reject(new Error(`角度(yaw=${yaw},pitch=${pitch},roll=${roll})的透视图提取失败，退出码: ${code}`))
        }
      })

      ffmpegProcess.on('error', (error) => {
        reject(new Error(`角度(yaw=${yaw},pitch=${pitch},roll=${roll})的透视图提取错误: ${error.message}`))
      })
    })
  }

  /**
   * 从全景照片中提取透视图
   * @param inputDir 输入目录路径
   * @param outputDir 输出目录
   * @param projectionType 投影类型：'5views' 或 '8views'
   * @param onProgress 进度回调
   */
  async extractPanoramaPhotoProjections(
    inputDir: string,
    outputDir: string,
    projectionType: '5views' | '8views' = '8views',
    resolution: string = '1920x1080',
    onProgress?: (log: string) => void
  ): Promise<void> {
    return new Promise((resolve, reject) => {
      const ffmpegPath = this.getFfmpegPath()
      
      // 检查FFMpeg是否存在
      if (!fs.existsSync(ffmpegPath)) {
        throw new Error(`FFMpeg未找到: ${ffmpegPath}`)
      }

      // 检查输入目录是否存在
      if (!fs.existsSync(inputDir)) {
        throw new Error(`输入目录不存在: ${inputDir}`)
      }

      // 确保输出目录存在
      if (!fs.existsSync(outputDir)) {
        fs.mkdirSync(outputDir, { recursive: true })
      }

      // 定义透视图配置
      let projections: Array<{id: string, name: string, yaw: number, pitch: number, roll: number}> = []
      
      if (projectionType === '5views') {
        // 5视图模式：前、后、左、右、上
        projections = [
          { id: 'front', name: '前', yaw: 0, pitch: 0, roll: 0 },
          { id: 'back', name: '后', yaw: 180, pitch: 0, roll: 0 },
          { id: 'left', name: '左', yaw: -90, pitch: 0, roll: 0 },
          { id: 'right', name: '右', yaw: 90, pitch: 0, roll: 0 },
          { id: 'up', name: '上', yaw: 0, pitch: -90, roll: 0 }
        ]
      } else {
        // 8视图模式：前俯视、前仰视、后俯视、后仰视、左俯视、左仰视、右俯视、右仰视
        projections = [
          { id: 'front-down', name: '前俯视', yaw: 0, pitch: -30, roll: 0 },
          { id: 'front-up', name: '前仰视', yaw: 0, pitch: 30, roll: 0 },
          { id: 'back-down', name: '后俯视', yaw: 180, pitch: -30, roll: 0 },
          { id: 'back-up', name: '后仰视', yaw: 180, pitch: 30, roll: 0 },
          { id: 'left-down', name: '左俯视', yaw: -90, pitch: -30, roll: 0 },
          { id: 'left-up', name: '左仰视', yaw: -90, pitch: 30, roll: 0 },
          { id: 'right-down', name: '右俯视', yaw: 90, pitch: -30, roll: 0 },
          { id: 'right-up', name: '右仰视', yaw: 90, pitch: 30, roll: 0 }
        ]
      }

      // 创建各个角度的子目录
      for (const projection of projections) {
        const projPath = path.join(outputDir, projection.id)
        if (!fs.existsSync(projPath)) {
          fs.mkdirSync(projPath)
        }
      }

      onProgress?.(`开始提取全景照片${projectionType === '5views' ? '5视图' : '8视图'}透视图: ${inputDir} -> ${outputDir}`)

      try {
        // 读取输入目录中的jpg文件
        const files = fs.readdirSync(inputDir).filter(file => 
          file.toLowerCase().endsWith('.jpg') && fs.statSync(path.join(inputDir, file)).isFile()
        )

        if (files.length === 0) {
          throw new Error(`输入目录中没有找到jpg文件: ${inputDir}`)
        }

        // 处理每个jpg文件
        const processPromises = files.map(async (file) => {
          const inputFile = path.join(inputDir, file)
          const fileName = path.basename(file, '.jpg')
          
          onProgress?.(`处理文件: ${file}`)
          
          // 对每个文件提取所有角度
          await Promise.all(projections.map(async (projection) => {
            const outputFile = path.join(outputDir, projection.id, `${fileName}_${projection.id}.jpg`)
            await this.extractSinglePhotoProjection(
              inputFile,
              outputFile,
              projection.yaw,
              projection.pitch,
              projection.roll,
              resolution,
              onProgress
            )
          }))
        })

        Promise.all(processPromises).then(() => {
          onProgress?.(`全景照片${projectionType === '5views' ? '5视图' : '8视图'}透视图提取完成: ${outputDir}`)
          resolve()
        }).catch(error => {
          reject(error)
        })
      } catch (error) {
        reject(error)
      }
    })
  }

  /**
   * 从单个全景照片中提取特定角度的透视图
   */
  private async extractSinglePhotoProjection(
    inputFile: string,
    outputFile: string,
    yaw: number,
    pitch: number,
    roll: number,
    resolution: string,
    onProgress?: (log: string) => void
  ): Promise<void> {
    return new Promise((resolve, reject) => {
      const ffmpegPath = this.getFfmpegPath()
      
      // 解析分辨率
      // const [width, height] = resolution.split('x').map(Number);
      const [width] = resolution.split('x').map(Number);
      // 构建v360滤镜参数，使用用户提供的成功命令格式
      const v360Filter = `v360=input=e:output=rectilinear:yaw=${yaw}:pitch=${pitch}:roll=${roll}:h_fov=90:v_fov=90:w=${width}:h=${width}`

      const args = [
        '-i', inputFile,
        '-vf', v360Filter,
        '-frames:v', '1',
        '-y', // 覆盖现有文件
        outputFile
      ]

      onProgress?.(`开始提取照片角度(yaw=${yaw},pitch=${pitch},roll=${roll})的透视图`)
      
      const ffmpegProcess = spawn(ffmpegPath, args)

      ffmpegProcess.stdout.on('data', (data) => {
        const log = data.toString().trim()
        if (log) {
          onProgress?.(`INFO (yaw=${yaw},pitch=${pitch}): ${log}`)
        }
      })

      ffmpegProcess.stderr.on('data', (data) => {
        const log = data.toString().trim()
        if (log) {
          onProgress?.(`FFMPEG (yaw=${yaw},pitch=${pitch}): ${log}`)
        }
      })

      ffmpegProcess.on('close', (code) => {
        if (code === 0) {
          onProgress?.(`照片角度(yaw=${yaw},pitch=${pitch},roll=${roll})的透视图提取完成: ${outputFile}`)
          resolve()
        } else {
          reject(new Error(`照片角度(yaw=${yaw},pitch=${pitch},roll=${roll})的透视图提取失败，退出码: ${code}`))
        }
      })

      ffmpegProcess.on('error', (error) => {
        reject(new Error(`照片角度(yaw=${yaw},pitch=${pitch},roll=${roll})的透视图提取错误: ${error.message}`))
      })
    })
  }
}